[bits 32]
section .text

global switch_to

; switch_to(struct task_struct cur, struct task_struct next)
switch_to:
    ; ------------------ 保存当前线程环境 ---------------------
    push esi
    push edi
    push ebx
    push ebp

    mov eax, [esp + 20] ; 参数 cur = [esp + 20]
    mov [eax], esp      ; 将当前线程 esp 保存到 task_struct 的 self_kstack 字段
                        ; self_kstack 的位置在 task_struct 中偏移量为 0
                        ; 因此 task_struct 的地址便是 self_kstack 的地址

    ; ------------------ 恢复要切换的下一个线程所对应环境 ---------------------
    mov eax, [esp + 24] ; 参数 next = [esp + 24]
    mov esp, [eax]      ; 将要切换的下一个线程中的 esp 从该线程 task_struct 中的 self_kstack 取出来

    pop ebp
    pop ebx
    pop edi
    pop esi

    ret ; 有两种返回结果
            ; 1. 要切换的线程之前尚未执行过，处于第一次执行的状态，此时栈顶是函数 kernel_thread 的地址，执行 ret 会去执行 kernel_thread() 函数
            ; 2. 已经执行过了，不再是第一次执行，此时 switch_to() 是由 schedule() 所调用的，栈顶保存的自然是 schedule 的地址，执行 ret 后会去执行 schedule 剩下的代码
